package ift585.tp2;

import java.io.*;
import java.util.*;

public class MessageUtility {
	private static final int IS_HOST_OFFSET = 2;
	private static final int COST_OFFSET = 1;
	private static final int ADDRESS_OFFSET = 0;
	private static final String PAIR_VALUES_SPLITER = ",";

	// serialiseRoutingTable
	
	public static byte [] serializeRoutingTable(Map<String, Pair> nodeMap) throws IOException{

		Set<String> keys = nodeMap.keySet();

		// Format de la serialization : <clee>adresse,cout</clee> ... <derniereclee>adresse,cout</dreniereclee>; 
		StringBuilder serialization = new StringBuilder();
		
		for(String key : keys){
			serialization.append("<" + key + ">" + nodeMap.get(key).getAdresse() + PAIR_VALUES_SPLITER + nodeMap.get(key).getCout() + "</" + key + ">");
		}
		
		serialization.append(";");
		
		return serialization.toString().getBytes();
	}
	
	// unserialiseRoutingTable
	
	public static Map<String, Pair> unserializeRoutingTable(byte [] payload) throws IOException, ClassNotFoundException{
		StringBuilder rebuildHashMap = new StringBuilder();
		
		for(int i = 0 ; i < payload.length ; ++i){
			rebuildHashMap.append((char)payload[i]);
		}
		
		// Format de la serialization : <clee>adresse,cout</clee> ... <derniereclee>adresse,cout</dreniereclee>; 
		
		int cpt = 0;
		char charAt;
		
		Map<String, Pair> routingTable = new HashMap<String, Pair>();
		
		while( (charAt = rebuildHashMap.charAt(cpt)) != ';'){
			if(charAt == '<'){
				
				// skip character '<'
				cpt++;
				
				StringBuilder key = new StringBuilder();
				
				while((charAt = rebuildHashMap.charAt(cpt)) != '>'){	// Advance until end of key
					key.append(charAt);
					cpt++;
				}
				
				cpt++; // skip character '>'
				
				StringBuilder values = new StringBuilder();
				
				while((charAt = rebuildHashMap.charAt(cpt)) != '<'){	// Advance until end of key
					values.append(charAt);
					cpt++;
				}
				
				while((charAt = rebuildHashMap.charAt(cpt)) != '>'){	// Advance until key ending as </keys> expected
					cpt++;
				}
				
				// skip character '>'
				cpt++;
				
				// Key / value retreived
				String [] pairValue = values.toString().split(PAIR_VALUES_SPLITER);
				String newKey = key.toString();
				
				routingTable.put(newKey, new Pair(pairValue[ADDRESS_OFFSET], Integer.valueOf(pairValue[COST_OFFSET])));
			}
		}
		
		
		return routingTable;
	}
	
	// serialiseInfoRouter
	public static byte [] serializeInfoRouter(String address, Vector<Neighbors> neighbors) throws IOException{
		
		StringBuilder serializedVector = new StringBuilder();
		
		serializedVector.append("<[" + address + "]>");
		
		for(int i = 0 ; i < neighbors.size() ; ++i){
			serializedVector.append("<" + neighbors.get(i).getAddress() + "," + neighbors.get(i).getCost() + "," +  neighbors.get(i).estHost() + ">");
		}
		
		serializedVector.append(";");
		
		return serializedVector.toString().getBytes();
	}
	
	// unserializeInfoRouter
	public static InfoRouter unserializeInfoRouter(byte [] payload) throws IOException, ClassNotFoundException{
		
		String address = new String();
		Vector<Neighbors> neighbors = new Vector<Neighbors>();
		StringBuilder serializedNeighbors = new StringBuilder();

		for(int i = 0 ; i < payload.length ; ++i){
			serializedNeighbors.append((char) payload[i]);
		}
		
		char charAt;
		int cpt = 0;
		
		// skip character '['
		cpt++;
		
		// skip character '<'
		cpt++;
		
		while((charAt = serializedNeighbors.charAt(cpt)) != ']'){
			address += charAt;
			cpt++;
		}
		
		// skip character ']'
		cpt++;
		
		// skip character '>'
		cpt++;
		
		while((charAt = serializedNeighbors.charAt(cpt)) != ';'){

			// skip character '<'
			cpt++;
			
			String values = new String("");
			
			while((charAt = serializedNeighbors.charAt(cpt)) != '>'){
				values += charAt;
				cpt++;
			}
			
			// skip character '>'
			cpt++;
			
			String [] neighborsValues = values.toString().split(PAIR_VALUES_SPLITER);
			
			neighbors.add(new Neighbors(neighborsValues[ADDRESS_OFFSET], Integer.valueOf(neighborsValues[COST_OFFSET]), Boolean.valueOf(neighborsValues[IS_HOST_OFFSET])));
		}
		
		InfoRouter infos = new InfoRouter();
		
		infos.address = address;
		infos.immediateNeighbors = neighbors;
		
		return infos;
	}
	
	// serializeSimpleMessage
	public static byte[] serializeMessage(Message toSerialize) throws IOException{
		
		StringBuilder serializedMessage = new StringBuilder();
		
		serializedMessage.append( "<" + toSerialize.getMessageType() + ">");
		serializedMessage.append("<" + toSerialize.getSender() + ">");
		serializedMessage.append("<" + toSerialize.getNextHop() + ">");
		serializedMessage.append("<" + toSerialize.getReceiver()+ ">");
		serializedMessage.append("<" + toSerialize.getStringPayload() + ">");
		serializedMessage.append(";");
		
		return serializedMessage.toString().getBytes();
	}
	
	// unserializeSimpleMessage
	public static Message unserializeMessage(byte [] payload){
		
		String messageType = new String();
		String sender = new String();
		String nextHop = new String();
		String receiver = new String();
		String data = new String();
		
		
		StringBuilder serializedData = new StringBuilder();
		
		for(int i = 0 ; i < payload.length ; ++i){
			serializedData.append((char)payload[i]);
		}

		char charAt;
		int cpt = 0;
		
		while((charAt = serializedData.charAt(cpt)) != ';'){
			
			// skip character '<'
			
			cpt++;
			
			while((charAt = serializedData.charAt(cpt)) != '>'){
				messageType += charAt;
				cpt++;
			}
			
			// skip character '>'
			cpt++;
			
			// skip character '<'
			cpt++;
			
			while((charAt = serializedData.charAt(cpt)) != '>'){
				sender += charAt;
				cpt++;
			}
			
			// skip character '>'
			cpt++;
			
			// skip character '<'
			cpt++;
			
			while((charAt = serializedData.charAt(cpt)) != '>'){
				nextHop += charAt;
				cpt++;
			}
			
			// skip character '>'
			cpt++;
			
			// skip character '<'
			cpt++;
			
			while((charAt = serializedData.charAt(cpt)) != '>'){
				receiver += charAt;
				cpt++;
			}
			
			// skip character '>'
			cpt++;
			
			// skip character '<'
			cpt++;
			
			while((charAt = serializedData.charAt(cpt)) != ';'){
				data += charAt;
				cpt++;
			}
			data += charAt;
			// skip character ';'
			cpt++;
			
			// skip character '>'
			cpt++;			
		}
		
		return new Message(receiver, nextHop, sender, Byte.valueOf(messageType), data.getBytes());
	}
	
	public static byte [] serializeStringMessage(String toSend){
		StringBuilder builder = new StringBuilder();
		
		builder.append("<" + toSend + ">" + ";");
		
		return builder.toString().getBytes();
	}
	
	public static String unserializeStringMessage(byte [] payload){
		StringBuilder builder = new StringBuilder();
		
		for(int i = 0 ; i < payload.length ; ++i){
			builder.append((char) payload[i]);
		}
		
		String messageToDeliver = new String();
		
		char oneChar;
		int cpt = 0;
		
		while((oneChar = builder.charAt(cpt)) != ';'){
			// skip character '<'
			cpt++;
			
			while((oneChar = builder.charAt(cpt)) != '>'){
				messageToDeliver += oneChar;
				cpt++;
			}
			
			// skip character '>'
			cpt++;
		}
		
		return messageToDeliver;
	}
}
